Make the site findable, in both languages - #64
Merged
Conversation
Both pages already read in one language and already take it from `?lang=`, which is where App Store Connect's per-localization URLs point. What was missing is that nothing said so. A crawler renders the page, the script negotiates from navigator.languages — `en-US` for Googlebot — and the Japanese half goes display:none, on the one URL anybody links to. So the Japanese page was not ranked badly; it did not exist. Three things fix that, and none of them changes how the site works. hreflang alternates in both heads, naming `?lang=en`, `?lang=ja` and the bare URL as x-default. The set is identical on every variant, self-reference included, which is what lets one file serve all three. There is deliberately no rel=canonical: it would have to differ per URL, and a static one pointing anywhere folds the other two into it and un-indexes the Japanese page, while a script-written one is the case Google says not to rely on. Real links in both footers. The picker is a <select>, which a crawler cannot follow, so until now the Japanese URL was declared in the head and reachable from nowhere. And a per-language meta description, carried on the section like the title already was, so adding a language is still a code, an <option> and a translated <section>. The static one stays bilingual, because that is what the bare URL and a script-less reader get. The OG card stays single and stays English, and the comment saying why now says the real reason: a social scraper does not run the script that picks a language, so per-language cards would have to be written by JavaScript nothing would execute.
A sitemap and a structured-data block, which is the rest of what the search turned up. Neither changes a word the reader sees. site/sitemap.xml lists six URLs rather than two: an hreflang set names every variant from every variant, so each of the three addresses each page answers to gets an entry carrying the whole set. It has no lastmod, changefreq or priority — Google ignores the last two, and lastmod only counts while it is honest, which a hand-deployed site would not keep it. It is meant to be submitted in Search Console rather than announced from a robots.txt, and that is not a preference. A robots.txt is only read at the host root — temoki.github.io/robots.txt — which belongs to no repository here, so one added to site/ would be served, ignored, and easy to mistake for working. A sitemap may sit at any level at or above what it lists. The JSON-LD is the weakest item of the four and is written to stay checkable: the price, the family rating and the seller come from the App Store listing, the license from LICENSE, the requirements from the specs table further down the page. It carries no aggregateRating, and must not grow one that nobody left.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits, because they are two different things. Neither changes a word
the reader sees, and neither changes how the site works.
The Japanese page did not exist
A crawler renders the page, which means it negotiates like a browser.
Googlebot's
navigator.languagesisen-US, so the script resolvesen,html[data-lang] section[lang] { display: none }hides the whole Japanese<section>, and that happens on the one URL anybody links to. The Japanesepage was not ranking badly — there was nothing there to rank.
Verified in headless Chrome against a local copy of
site/, which is thesame renderer Google uses:
data-lang/(Accept-Language en-US)en/?lang=enen/?lang=jajaSo the mechanism was already there —
?lang=is what App Store Connect'sper-localization URLs point at, and it renders a genuinely different page.
Nothing declared it. This adds the three things that do: hreflang alternates
naming
?lang=en,?lang=jaand the bare URL asx-default; real<a href="?lang=…">links in both footers, because a<select>is notsomething a crawler can follow and the Japanese URL was otherwise reachable
from nowhere; and a per-language
<meta name="description">, carried on thesection beside the
data-titlethat was already there.No
rel=canonical, deliberately. It would have to differ per URL, and onefile cannot say three things: a static one pointing anywhere folds the other
two into it and un-indexes the Japanese page, while a script-written one is
the case Google says not to rely on. hreflang carries the relationship.
The no-JS rule still holds, though it is argued from the source rather than
rendered — Chrome cannot
--dump-domwith scripting disabled. The served<html>tag has nodata-lang, that attribute is written only by the inlinescript, and it is what the hiding rule keys on; this change touches no CSS
and no
<html>tag.A sitemap and a structured-data block
site/sitemap.xmllists six URLs rather than two: an hreflang set names everyvariant from every variant. No
lastmod— the site is deployed by hand atrelease time, so it would go stale the first time someone forgot it, and
Google ignores a lastmod it cannot trust.
No
robots.txt, and that is not an oversight. A robots.txt is only readat the host root,
temoki.github.io/robots.txt, which belongs to norepository here. One added to
site/would be served, ignored, and easy tomistake for working. The sitemap gets submitted in Search Console instead — a
sitemap may sit at any level at or above the URLs it lists.
The JSON-LD is the weakest of the four items and is written to stay checkable:
price, family rating and seller from the App Store listing, the license from
LICENSE, the requirements from the specs table further down the page. Itcarries no
aggregateRatingand must not grow one nobody left. AnalternateNamein katakana was written and then removed — the app's JapaneseApp Store name is "Tortoise Blocks", so the katakana form was invented.
Deploying
pages.ymlis dispatch-only, so this needs a run against main after merge.main's
site/is what is serving now, so that deploy publishes exactly thesechanges. The sitemap can only be submitted after that, since Search Console
fetches it to accept it.